package com.hemerasolutions.v2trainer.model.exercise.intensity;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.TimeZone;

import com.hemerasolutions.v2trainer.model.base.BaseModel;
import com.hemerasolutions.v2trainer.model.exercise.PhysicalCapacity;
import com.hemerasolutions.v2trainer.model.unit.intensity.IntensityUnit;
import com.hemerasolutions.v2trainer.model.unit.intensity.Rpe;
import com.hemerasolutions.v2trainer.model.unit.volume.VolumeFactor;

import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;

import org.springframework.expression.EvaluationContext;
import org.springframework.expression.Expression;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;

@Entity
public class IntensityZone extends BaseModel {
 
	private static final long serialVersionUID = 1L;
	
    @Column( length = 2 )
	private int position;

    @Column( length = 30 )
	private String name;
    
    @Column( length = 30 )
	private String alias;

    @Column( length = 7 )
	private String color;

    @Column
    private long uaFactor = 1 ;

    @Column
    private Date concentricTime;

    @Column
    private Date eccentricTime;

    @ManyToOne
    private VolumeFactor speedVolumeFactor;
    
    @Column
    private double averageSpeed;

    @ManyToOne
    private Rpe lowRpe;

    @ManyToOne
    private Rpe highRpe;
    
    @ManyToOne
	private PhysicalCapacity physicalCapacity;
	
	@ManyToOne
	private IntensityTable intensityTable;
	
	@OneToMany(mappedBy="intensityZone", fetch=FetchType.LAZY ,cascade=CascadeType.ALL,orphanRemoval=true)
	private List<Intensity> intensitys;
	
	
	public IntensityZone() {
		super();
		this.intensitys = new ArrayList<Intensity>();
	}


	public IntensityZone(IntensityTable it) {
		super();
		
		this.id = null;
		this.position = it.getIntensitys().size();
		this.intensityTable = it;
		this.intensitys = new ArrayList<Intensity>();
		
		
		for(IntensityUnit iu:it.getIntensityUnits()){
        	Intensity i = new Intensity(iu,this);
        	this.intensitys.add(i);
    	}		
	}
	

	public IntensityZone(IntensityModZone other,IntensityTable it){
		super();
		this.id = null;
		this.name = other.getName();
		this.position = other.getPosition();
		this.physicalCapacity = other.getPhysicalCapacity();
		this.color = other.getColor();
		this.alias = other.getAlias();
		this.intensityTable = it;
		this.lowRpe = other.getLowRpe();
		this.highRpe = other.getHighRpe();
		this.intensitys = new ArrayList<Intensity>();
		
	}
	
	public IntensityZone(IntensityZone other, IntensityTable it){
		super();
		this.id = null;
		this.name = other.name;
		this.position = other.position;
		this.physicalCapacity = other.physicalCapacity;
		this.color = other.color;
		this.alias = other.alias;
		this.intensityTable = it;
		this.intensitys = new ArrayList<Intensity>();
		for(Intensity i:other.intensitys){
			this.intensitys.add(new Intensity(i,this));
		}
		this.uaFactor = other.uaFactor;
		this.averageSpeed = other.averageSpeed;
		this.eccentricTime = other.eccentricTime;
		this.concentricTime = other.concentricTime;
		this.lowRpe = other.lowRpe;
		this.highRpe = other.highRpe;
		
	}
	

	public Date getDateAverageSpeed() {

		Calendar c = Calendar.getInstance();
		c.setTimeZone(TimeZone.getTimeZone("Etc/GMT0"));

		if(averageSpeed != 0){
			c.setTimeInMillis((long)this.getAverageSpeed()*1000);
		}else{
			c.setTimeInMillis(0);
		}

		return c.getTime();
	}

	public void setDateAverageSpeed(Date dateAverageSpeed) {

		Calendar c = Calendar.getInstance();
		c.setTimeZone(TimeZone.getTimeZone("Etc/GMT0"));

		if(dateAverageSpeed != null){
			c.setTime(dateAverageSpeed);
			if(c.getTimeInMillis() == 0){
				this.averageSpeed = 0;
			}else{
				this.setAverageSpeed((double)c.getTimeInMillis()/1000);
			}
		}else{
			this.averageSpeed = 0;
		}

	}
	
	
	public Double getRealAverageSpeed(){
		return this.averageSpeed;
	}
	
	public double getAverageSpeed() {
		if(this.speedVolumeFactor != null && averageSpeed != 0 ){
			EvaluationContext context 	= new StandardEvaluationContext(); 
			ExpressionParser parser 	= new SpelExpressionParser();
			Expression exp = null;

		
			context.setVariable("value", averageSpeed);
			exp = parser.parseExpression( this.speedVolumeFactor.getUpFormula());
			
			return (double) exp.getValue(context);
		}else{
			return averageSpeed ;
			
		}
	}

	public void setAverageSpeed(double averageSpeed) {
		if(this.speedVolumeFactor != null && averageSpeed != 0 ){
			EvaluationContext context 	= new StandardEvaluationContext(); 
			ExpressionParser parser 	= new SpelExpressionParser();
			Expression exp = null;
			 
			context.setVariable("value", averageSpeed);
			exp = parser.parseExpression( this.speedVolumeFactor.getDownFormula());
			
			this.averageSpeed = (double) exp.getValue(context);			
		}else{
			this.averageSpeed = averageSpeed  ;
		}

	}		

	
	public IntensityZone unitIntensityUnitZone (int i){
		IntensityZone iz = null;
		
		if(this.intensitys != null && !this.intensitys.isEmpty()){
			iz = this.intensitys.get(i).getIntensityZone();
		}
		
		return iz;
	}
		
	
	public static long getSerialversionuid() {
		return serialVersionUID;
	}


	public int getPosition() {
		return position;
	}

	public String getName() {
		return name;
	}


	public String getColor() {
		return color;
	}


	public List<Intensity> getIntensitys() {
		return intensitys;
	}

	public void setIntensitys(List<Intensity> intensitys) {
		this.intensitys = intensitys;
	}

	public void setPosition(int position) {
		this.position = position;
	}

	public void setName(String name) {
		this.name = name;
	}

	public void setColor(String color) {
		this.color = color;
	}

	public IntensityTable getIntensityTable() {
		return intensityTable;
	}

	public void setIntensityTable(IntensityTable itensityTable) {
		this.intensityTable = itensityTable;
	}

	public PhysicalCapacity getPhysicalCapacity() {
		return physicalCapacity;
	}

	public void setPhysicalCapacity(PhysicalCapacity physicalCapacity) {
		this.physicalCapacity = physicalCapacity;
	}

	public String getAlias() {
		return alias;
	}

	public void setAlias(String alias) {
		this.alias = alias;
	}

	
	public long getUaFactor() {
		return uaFactor;
	}


	public void setUaFactor(long uaFactor) {
		this.uaFactor = uaFactor;
	}

	public void setAverageSpeed(long averageSpeed) {
		this.averageSpeed = averageSpeed;
	}


	
	public Rpe getLowRpe() {
		return lowRpe;
	}


	public void setLowRpe(Rpe lowRpe) {
		this.lowRpe = lowRpe;
	}


	public Rpe getHighRpe() {
		return highRpe;
	}


	public void setHighRpe(Rpe highRpe) {
		this.highRpe = highRpe;
	}


	public Date getConcentricTime() {
		return concentricTime;
	}


	public void setConcentricTime(Date concentricTime) {
		this.concentricTime = concentricTime;
	}


	public Date getEccentricTime() {
		return eccentricTime;
	}


	public void setEccentricTime(Date eccentricTime) {
		this.eccentricTime = eccentricTime;
	}


	public VolumeFactor getSpeedVolumeFactor() {
		return speedVolumeFactor;
	}


	public void setSpeedVolumeFactor(VolumeFactor speedVolumeFactor) {
		this.speedVolumeFactor = speedVolumeFactor;
	}


	/* (non-Javadoc)
	 * @see java.lang.Object#hashCode()
	 */
	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + ((alias == null) ? 0 : alias.hashCode());
		long temp;
		temp = Double.doubleToLongBits(averageSpeed);
		result = prime * result + (int) (temp ^ (temp >>> 32));
		result = prime * result + ((color == null) ? 0 : color.hashCode());
		result = prime * result
				+ ((concentricTime == null) ? 0 : concentricTime.hashCode());
		result = prime * result
				+ ((eccentricTime == null) ? 0 : eccentricTime.hashCode());
		result = prime * result + ((highRpe == null) ? 0 : highRpe.hashCode());
		result = prime * result + ((id == null) ? 0 : id.hashCode());
		result = prime * result
				+ ((intensityTable == null) ? 0 : intensityTable.hashCode());
		result = prime * result + ((lowRpe == null) ? 0 : lowRpe.hashCode());
		result = prime * result + ((name == null) ? 0 : name.hashCode());
		result = prime
				* result
				+ ((physicalCapacity == null) ? 0 : physicalCapacity.hashCode());
		result = prime * result + position;
		result = prime
				* result
				+ ((speedVolumeFactor == null) ? 0 : speedVolumeFactor
						.hashCode());
		result = prime * result + (int) (uaFactor ^ (uaFactor >>> 32));
		return result;
	}


	/* (non-Javadoc)
	 * @see java.lang.Object#equals(java.lang.Object)
	 */
	@Override
	public boolean equals(Object obj) {
		if (this == obj) {
			return true;
		}
		if (obj == null) {
			return false;
		}
		if (getClass() != obj.getClass()) {
			return false;
		}
		IntensityZone other = (IntensityZone) obj;
		if (alias == null) {
			if (other.alias != null) {
				return false;
			}
		} else if (!alias.equals(other.alias)) {
			return false;
		}
		if (Double.doubleToLongBits(averageSpeed) != Double
				.doubleToLongBits(other.averageSpeed)) {
			return false;
		}
		if (color == null) {
			if (other.color != null) {
				return false;
			}
		} else if (!color.equals(other.color)) {
			return false;
		}
		if (concentricTime == null) {
			if (other.concentricTime != null) {
				return false;
			}
		} else if (!concentricTime.equals(other.concentricTime)) {
			return false;
		}
		if (eccentricTime == null) {
			if (other.eccentricTime != null) {
				return false;
			}
		} else if (!eccentricTime.equals(other.eccentricTime)) {
			return false;
		}
		if (highRpe == null) {
			if (other.highRpe != null) {
				return false;
			}
		} else if (!highRpe.equals(other.highRpe)) {
			return false;
		}
		if (id == null) {
			if (other.id != null) {
				return false;
			}
		} else if (!id.equals(other.id)) {
			return false;
		}
		if (intensityTable == null) {
			if (other.intensityTable != null) {
				return false;
			}
		} else if (!intensityTable.equals(other.intensityTable)) {
			return false;
		}
		if (lowRpe == null) {
			if (other.lowRpe != null) {
				return false;
			}
		} else if (!lowRpe.equals(other.lowRpe)) {
			return false;
		}
		if (name == null) {
			if (other.name != null) {
				return false;
			}
		} else if (!name.equals(other.name)) {
			return false;
		}
		if (physicalCapacity == null) {
			if (other.physicalCapacity != null) {
				return false;
			}
		} else if (!physicalCapacity.equals(other.physicalCapacity)) {
			return false;
		}
		if (position != other.position) {
			return false;
		}
		if (speedVolumeFactor == null) {
			if (other.speedVolumeFactor != null) {
				return false;
			}
		} else if (!speedVolumeFactor.equals(other.speedVolumeFactor)) {
			return false;
		}
		if (uaFactor != other.uaFactor) {
			return false;
		}
		return true;
	}


	/* (non-Javadoc)
	 * @see java.lang.Object#toString()
	 */
	@Override
	public String toString() {
		return "IntensityZone [id=" + id + ", position=" + position + ", name="
				+ name + ", alias=" + alias + ", color=" + color
				+ ", uaFactor=" + uaFactor + ", concentricTime="
				+ concentricTime + ", eccentricTime=" + eccentricTime
				+ ", speedVolumeFactor=" + speedVolumeFactor
				+ ", averageSpeed=" + averageSpeed + ", lowRpe=" + lowRpe
				+ ", highRpe=" + highRpe + ", physicalCapacity="
				+ physicalCapacity + ", intensityTable=" + intensityTable + "]";
	}



	 
}
 
